package org.ytor.common.classmeta;

import lombok.Data;

import java.lang.annotation.Annotation;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * created by yangtong on 2025/4/15 16:54:24
 * 字段元数据
 */
@Data
public class FieldMetadata {
    /**
     * 字段名称
     */
    private final String name;
    /**
     * 字段反射对象
     */
    private final Field field;
    /**
     * 注解集合
     */
    private final Map<Class<? extends Annotation>, Annotation> annotations;

    /**
     * 字段类型/修饰符，便于判断与日志
     */
    private final Class<?> type;

    /**
     * 修饰符
     */
    private final int modifiers;

    /**
     * VarHandle 缓存
     */
    private volatile VarHandle cachedHandle;
    private final Object vhInitLock = new Object();

    public FieldMetadata(Field field) {
        this.name = field.getName();
        this.field = field;
        this.type = field.getType();
        this.modifiers = field.getModifiers();
        this.annotations = Arrays.stream(field.getAnnotations())
                .collect(Collectors.toMap(Annotation::annotationType, a -> a));
    }

    /**
     * 获取 obj 对象的字段值（内部使用 VarHandle）
     */
    public <T> Object get(T obj) throws IllegalAccessException {
        try {
            VarHandle vh = ensureVarHandle();
            if (Modifier.isStatic(modifiers)) {
                return vh.get();
            } else {
                return vh.get(obj);
            }
        } catch (IllegalAccessException e) {
            throw e; // 句柄初始化阶段的访问异常
        } catch (Throwable t) {
            // VarHandle 的 get 本身不抛受检异常，这里统一转成 IllegalAccessException 以兼容原签名
            IllegalAccessException iae = new IllegalAccessException(t.getMessage());
            iae.initCause(t);
            throw iae;
        }
    }

    /**
     * 设置 obj 对象的字段值（同样使用 VarHandle）
     */
    public <T> void set(T obj, Object value) throws IllegalAccessException {
        try {
            VarHandle vh = ensureVarHandle();
            if (Modifier.isStatic(modifiers)) {
                vh.set(value);
            } else {
                vh.set(obj, value);
            }
        } catch (IllegalAccessException e) {
            throw e;
        } catch (Throwable t) {
            IllegalAccessException iae = new IllegalAccessException(t.getMessage());
            iae.initCause(t);
            throw iae;
        }
    }

    @SuppressWarnings("unchecked")
    public <A extends Annotation> A getAnnotation(Class<A> type) {
        return (A) annotations.get(type);
    }

    public boolean hasAnnotation(Class<? extends Annotation> type) {
        return annotations.containsKey(type);
    }

    /* ============================ 字段修饰符 ============================ */

    public boolean isPublic() {
        return Modifier.isPublic(modifiers);
    }

    public boolean isProtected() {
        return Modifier.isProtected(modifiers);
    }

    public boolean isPrivate() {
        return Modifier.isPrivate(modifiers);
    }

    public boolean isStatic() {
        return Modifier.isStatic(modifiers);
    }

    public boolean isFinal() {
        return Modifier.isFinal(modifiers);
    }

    public boolean isVolatile() {
        return Modifier.isVolatile(modifiers);
    }

    public boolean isTransient() {
        return Modifier.isTransient(modifiers);
    }

    /* ============================ 内部工具 ============================ */

    private VarHandle ensureVarHandle() throws IllegalAccessException {
        VarHandle vh = cachedHandle;
        if (vh != null) return vh;

        synchronized (vhInitLock) {
            vh = cachedHandle;
            if (vh != null) return vh;

            try {
                // 使用 privateLookupIn 获取对声明类的“私有”访问权限的 Lookup
                MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(
                        field.getDeclaringClass(), MethodHandles.lookup());
                vh = lookup.unreflectVarHandle(field);
                cachedHandle = vh;
                return vh;
            } catch (IllegalAccessException | IllegalArgumentException e) {
                // 可选放宽：仅用于创建句柄；后续访问仍通过 VarHandle 完成
                try {
                    field.setAccessible(true); // 按需启用（注意模块边界下仍可能需要 --add-opens）
                    MethodHandles.Lookup fallback = MethodHandles.lookup();
                    vh = fallback.unreflectVarHandle(field);
                    cachedHandle = vh;
                    return vh;
                } catch (IllegalAccessException e2) {
                    IllegalAccessException iae = new IllegalAccessException(e2.getMessage());
                    iae.initCause(e2);
                    throw iae;
                }
            }
        }
    }
}
